---
title: SvelteKit + Hanko
sidebar_label: SvelteKit
keywords: [svelte, sveltekit]
sidebar_custom_props:
  docCardIconName: svelte
---


# SvelteKit

Learn how to quickly add authentication and user profile in your SvelteKit app using Hanko.

## Install `@teamhanko/hanko-elements`

Once you've initialized your app, installing hanko-elements provides you with access to the prebuilt components: `hanko-auth` and `hanko-profile`.

```shell npm2yarn
npm install @teamhanko/hanko-elements
```

## Add the Hanko API URL

Retrieve the API URL from the [Hanko console](https://cloud.hanko.io/) and place it in your `.env` file.

```sh title=".env"
PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io
```

:::info
  If you are self-hosting you need to provide the URL of your running Hanko
  backend.
:::

## Add `<hanko-auth>` component

The `<hanko-auth>` web component adds a login interface to your app. Begin by importing the register function from `@teamhanko/hanko-elements` into your Svelte component. Call it with the Hanko API URL as an argument to register `<hanko-auth>` with the browser's [CustomElementRegistry](https://developer.mozilla.org/de/docs/Web/API/CustomElementRegistry). Once done, use the `<hanko-auth>` element in your component.

Here, we utilize the `onAuthflowCompleted` custom event, which is triggered upon the successful completion of the auth flow, redirecting the user to a designated route.

```js title="HankoAuth.svelte" showLineNumbers
<script>
  import { onMount } from "svelte";
  import { goto } from "$app/navigation";
  import { register } from "@teamhanko/hanko-elements";
  import { env } from "$env/dynamic/public";
  const hankoApi = env.PUBLIC_HANKO_API_URL;

  const redirectAfterLogin = () => {
    goto("/dashboard");
  };

  onMount(async () => {
    register(hankoApi).catch((error) => {
      // handle error
    });
  });
</script>

<hanko-auth on:onAuthFlowCompleted={redirectAfterLogin} />
```

:::info
When incorporating any Hanko component in your `+page.svelte` file(routes), it is necessary to disable server-side rendering (SSR) by setting `ssr` to false in your `+page.ts` file.

```js filename="routes/login/+page.ts"
export const ssr = false;
```

**But why?**

The register function tries to set up the `<hanko-auth>` element for the browser. But, SvelteKit pre-renders pages before displaying them. Since it doesn't have access to the browser's window object during this pre-render phase, the registration of the custom element would fail.
:::


## Add `<hanko-profile>` component

The `<hanko-profile>` component provides an interface, where users can manage their email addresses and passkeys.

```js title="HankoProfile.svelte" showLineNumbers
<script>
  import { register } from "@teamhanko/hanko-elements";
  import { onMount } from "svelte";
  import { env } from "$env/dynamic/public";

  const hankoApi = env.PUBLIC_HANKO_API_URL;

  onMount(async () => {
    register(hankoApi).catch((error) => {
      // handle error
    });
  });
</script>

<hanko-profile />
```

## Implement logout functionality

You can use `@teamhanko/hanko-elements` to easily manage user logouts. Below, we make a logout button component that you can use anywhere.

```js title="LogoutButton.svelte" showLineNumbers
<script>
  import { Hanko } from "@teamhanko/hanko-elements";
  import { goto } from "$app/navigation";
  import { env } from "$env/dynamic/public";
  const hankoApi = env.PUBLIC_HANKO_API_URL;

  const hanko = new Hanko(hankoApi);
  const logout = () => {
    hanko.user.logout().catch((error) => {
      // handle error
    });
    goto("/login")
  };
</script>

<button on:click={logout}>Logout</button>
```

## Customize component styles

You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](https://github.com/teamhanko/hanko/tree/main/frontend/elements#ui-customization).

## Securing routes

To add JWT verification with Hanko in your application, we're using [jose library](https://www.npmjs.com/package/jose). However, you're free to choose any other suitable library. This hook will ensure secure access to specific routes, like `/dashboard` here, by checking for valid JWT. Here we define the Hanko API URL, extract and verify the JWT from cookies, and redirect unauthorized users to the login page.

```js filename="hooks.server.ts" showLineNumbers
import { type RequestEvent, redirect, type Handle } from "@sveltejs/kit";

import { jwtVerify, createRemoteJWKSet } from "jose";
import { env } from "$env/dynamic/public";

const hankoApiUrl = env.PUBLIC_HANKO_API_URL;

const authenticatedUser = async (event: RequestEvent) => {
  const { cookies } = event;
  const hanko = cookies.get("hanko");
  const JWKS = createRemoteJWKSet(
    new URL(`${hankoApiUrl}/.well-known/jwks.json`)
  );

  try {
    await jwtVerify(hanko ?? "", JWKS);
    return true;
  } catch {
    return false;
  }
};

export const handle: Handle = async ({ event, resolve }) => {
  const verified = await authenticatedUser(event);

  if (event.url.pathname.startsWith("/dashboard") && !verified) {
    throw redirect(303, "/login");
  }

  const response = await resolve(event);
  return response;
};
```
